#include <opencv2/core/types.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <stdio.h>
#include <opencv2/opencv.hpp>
#include "opencv_helper.hpp"

struct Pad
{
    int top;
    int bottom;
    int left;
    int right;
};

static
void draw_grid(cv::Mat& image, const Pad& pad)
{
    const int w = image.cols;
    const int h = image.rows;
    cv::Scalar line_color(0, 0, 255);

    cv::Point A(pad.left, pad.top);
    cv::Point B(w - pad.left, pad.top);
    cv::Point C(w - pad.left, h - pad.top);
    cv::Point D(pad.left, h - pad.top);

    //  A      M       B
    //
    //  N      P       Q
    //
    //  D      R       C

    cv::Point M = (A + B) / 2;
    cv::Point N = (A + D) / 2;
    cv::Point P(M.x, N.y);
    cv::Point Q = (B + C) / 2;
    cv::Point R = (D + C) / 2;

    cv::line(image, A, B, line_color);
    cv::line(image, B, C, line_color);
    cv::line(image, C, D, line_color);
    cv::line(image, D, A, line_color);

    cv::line(image, N, Q, line_color);
    cv::line(image, M, R, line_color);

    const int block_height = ( (h - pad.top - pad.bottom) / 2 ) / 10;
    const int block_width = ( (w - pad.left - pad.right) / 2) / 15;

    for (int i = 0; i < 10; i++)
    {
        cv::Point start_pt(pad.left, i * block_height + pad.top);
        cv::Point end_pt(w / 2, i * block_height + pad.top);
        cv::line(image, start_pt, end_pt, line_color);
    }

    for (int i = 0; i < 15; i++)
    {
        cv::Point start_pt(pad.left + i * block_width, pad.top);
        cv::Point end_pt(start_pt.x, h / 2);
        cv::line(image, start_pt, end_pt, line_color);
    }
}

static
cv::Point get_grid_point(const cv::Size& grid, const Pad& pad, int x, int y)
{
    return cv::Point(pad.left + grid.width * x, pad.top + y * grid.height);
}


/// @brief 绘制五星红旗， 并旋转一定角度
/// @param rotate_angle 旋转的角度
static
void draw_five_pointed_star(cv::Mat& image, float rotate_angle = 0)
{
    cv::Size size = image.size();

    std::vector<cv::Point> pts = och::get_regular_polygon_vertices(size, 5);
    cv::Point A = pts[0];
    cv::Point B = pts[1];
    cv::Point C = pts[2];
    cv::Point D = pts[3];
    cv::Point E = pts[4];

    cv::Scalar line_color(0);

    // the center point
    cv::Point O(size.width / 2, size.height / 2);

    // rotate_angle
    const int w = image.cols;
    const int h = image.rows;
    float theta = och::degree_to_radian(rotate_angle);
    cv::Point rA = get_rotated_point(A, O, w, h, theta);
    cv::Point rB = get_rotated_point(B, O, w, h, theta);
    cv::Point rC = get_rotated_point(C, O, w, h, theta);
    cv::Point rD = get_rotated_point(D, O, w, h, theta);
    cv::Point rE = get_rotated_point(E, O, w, h, theta);

    cv::line(image, rE, rC, line_color);
    cv::line(image, rC, rA, line_color);
    cv::line(image, rA, rD, line_color);
    cv::line(image, rD, rB, line_color);
    cv::line(image, rB, rE, line_color);
}

static
void draw_circles(cv::Mat& image, const Pad& pad)
{
    // A              M
    //          T1
    //    S       T2
    //            T3
    ///         T4
    // N              P

    const int w = image.cols;
    const int h = image.rows;

    cv::Scalar line_color(0);
    cv::Size grid;
    grid.height = ( (h - pad.top - pad.bottom) / 2 ) / 10;
    grid.width = ( (w - pad.left - pad.right) / 2) / 15;

    //cv::Point S(5 * grid.width + pad.left, 5 * grid.height + pad.top);
    cv::Point S = get_grid_point(grid, pad, 5, 5);
    int big_radius = 3 * grid.width;
    const int small_radius = 1 * grid.width;

    cv::Point T1 = get_grid_point(grid, pad, 10, 2);
    cv::Point T2 = get_grid_point(grid, pad, 12, 4);
    cv::Point T3 = get_grid_point(grid, pad, 12, 7);
    cv::Point T4 = get_grid_point(grid, pad, 10, 9);

    // const int big_unit = 70;
    // const int small_unit = 25;

    cv::Mat S_roi = image(cv::Rect(S.x - big_radius, S.y - big_radius, big_radius * 2, big_radius * 2));
    draw_five_pointed_star(S_roi, 0);

    cv::Mat T1_roi = image(cv::Rect(T1.x - small_radius, T1.y - small_radius, small_radius * 2, small_radius * 2));
    draw_five_pointed_star(T1_roi, -20.f);

    cv::Mat T2_roi = image(cv::Rect(T2.x - small_radius, T2.y - small_radius, small_radius * 2, small_radius * 2));
    draw_five_pointed_star(T2_roi, 20.f);

    cv::Mat T3_roi = image(cv::Rect(T3.x - small_radius, T3.y - small_radius, small_radius * 2, small_radius * 2));
    draw_five_pointed_star(T3_roi);

    cv::Mat T4_roi = image(cv::Rect(T4.x - small_radius, T4.y - small_radius, small_radius * 2, small_radius * 2));
    draw_five_pointed_star(T4_roi, -20.f);

    cv::circle(image, S, big_radius, line_color);
    cv::circle(image, T1, small_radius, line_color);
    cv::circle(image, T2, small_radius, line_color);
    cv::circle(image, T3, small_radius, line_color);
    cv::circle(image, T4, small_radius, line_color);

    cv::line(image, S, T1, line_color);
    cv::line(image, S, T2, line_color);
    cv::line(image, S, T3, line_color);
    cv::line(image, S, T4, line_color);
}

int main()
{
    printf("Hello, World!\n");

    cv::Size size;
    size.width = 600 + 20;
    size.height = 400 + 20;
    cv::Mat image(size, CV_8UC3);
    image = cv::Scalar(255, 255, 255, 255);

    Pad pad;
    pad.left = 10;
    pad.right = 10;
    pad.top = 10;
    pad.bottom = 10;

    draw_circles(image, pad);
    draw_grid(image, pad); // done

    cv::imshow("image", image);
    cv::waitKey(0);

    return 0;
}

int main_odl()
{
    cv::Mat image = cv::imread("/home/zz/data/mask_girl.png");

    cv::Point T1(200, 200);
    const int roi_width = 100;
    const int roi_height = 100;
    cv::Rect rect(T1.x, T1.y, roi_width, roi_height);
    cv::Mat roi = image(rect).clone();
    //roi = cv::Scalar(0);

    cv::Point center(T1.x + roi_width / 2, T1.y + roi_height / 2);
    cv::Mat M1 = cv::getRotationMatrix2D(T1, 45, 1.0);
    cv::Mat res;
    cv::warpAffine(roi, res, M1, roi.size());

    cv::imshow("image", image);
    cv::imshow("roi", roi);
    cv::imshow("res", res);
    cv::waitKey(0);

    // 结论: cv::warpAffine() 不支持 inplace 操作。.. 结果会是全黑的

    return 0;
}